
import 'dart:convert';

import 'package:elmer_tools/common/GlobalState.dart';
import 'package:elmer_tools/common/HttpHelper.dart';
import 'package:elmer_tools/model/ResponseBody.dart';
import 'package:elmer_tools/service/ApiConfig.dart';
import 'package:elmer_tools/service/ApiEndPoint.dart';
import 'package:elmer_tools/service/ApiHost.dart';
import 'package:elmer_tools/service/ApiOption.dart';
import "package:http/http.dart" as http;

class ApiService {
    final ApiConfig config;
    late String _hostUrl;
    String runEnv;

    ApiService({required this.config, this.runEnv = "prod"}) {
        _hostUrl = getHostUrl(runEnv);
    }

    void setRunEnv(String env) {
        runEnv = env;
        _hostUrl = getHostUrl(runEnv);
    }

    ApiEndPoint getEndPoint(String name, String key) {
        Map<String, ApiEndPoint>?  endPoints = config.endpoints[name];
        if (endPoints == null) {
            throw Exception("EndPoint $name not found");
        }
        ApiEndPoint? endPoint = endPoints[key];
        if (endPoint == null) {
            throw Exception("EndPoint $name with key $key not found");
        }
        return ApiEndPoint(
            _hostUrl + endPoint.url,
            endPoint.method,
            endPoint.headers
        );
    }
    String getHostUrl(String env) {
        ApiHost? host = config.host.firstWhere((h) => h.env == env);
        if (host == null) {
            throw Exception("Host for environment $env not found");
        }
        return host.url;
    }

    Future<ResponseBody<T>> send<T>(String endPoint, [ApiOption? opt, T Function(Object? json)? fromJson]) async {

        ApiOption options = opt ?? ApiOption();

        List<String> strArr = endPoint.split(".");
        ApiEndPoint apiEndPoint = getEndPoint(strArr[0], strArr[1]);
        String url = apiEndPoint.url;
        String method = apiEndPoint.method.toUpperCase();

        if(url.contains("?") ) {
            url += _getQueryString(options.queryParams);
        } else {
            url += "?${_getQueryString(options.queryParams)}";
        }
        // Set headers
        Map<String, String> headers = apiEndPoint?.headers ?? {};
        if(GlobalState.token != null && GlobalState.token!.isNotEmpty) {
            headers["X-Token"] = GlobalState.token ?? "";
        }
        // send request
        http.Response response;
        if(method == "GET") {
            response = await HttpHelper.get(
                apiEndPoint.url,
                headers: headers
            );
        } else if(method == "POST") {
            response = await HttpHelper.post(
                apiEndPoint.url,
                headers: headers,
                body: jsonEncode(options.body),
            );
        } else if(method == "PUT") {
            response = await HttpHelper.put(
                apiEndPoint.url,
                headers: headers,
                body: jsonEncode(options.body),
            );
        } else if(method == "DELETE") {
            response = await HttpHelper.delete(
                apiEndPoint.url,
                headers: headers,
                body: jsonEncode(options.body),
            );
        } else {
            throw Exception("Unsupported HTTP method: $method");
        }
        if (response.statusCode < 200 || response.statusCode >= 300) {
            throw Exception("Request failed with status: ${response.statusCode}. Response: ${response.body}");
        } else {
            try {
                print("Response body: ${response.body}");
                if (response.body.isNotEmpty) {
                    if(T is String || T == String) {
                        return response.body as ResponseBody<T>; // Return raw string if T is String
                    } else {
                        Map<String, dynamic> jsonResponse = jsonDecode(response.body);
                        if(fromJson != null) {
                            return ResponseBody<T>.fromJson(jsonResponse, fromJson);
                        } else {
                            return ResponseBody<T>.fromJson(jsonResponse, (json) => json as T);
                        }
                    }
                } else {
                    return ResponseBody<T>(message: "", statusCode: "500"); // Return null if the response body is empty
                }
            } catch (e) {
                throw Exception("Failed to parse response: ${e.toString()}");
            }
        }
    }
 
    String _getQueryString(Map<String, String> params) {
        if (params.isEmpty) return '';
        return '?${params.entries.map((e) => '${e.key}=${Uri.encodeComponent(e.value.toString())}').join('&')}';
    }
    List<ApiHost> getApiHosts() {
        return config.host;
    }
}
